/**
 * @file blePro.c
 * @brief
 * @author  xiaowine (xiaowine@sina.cn)
 * @version 01.00
 * @date    2021-04-07
 *
 * @copyright Copyright (c) {2020}  xiaowine
 *
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2021-04-07 <td>1.0     <td>wangh     <td>内容
 * </table>
 * ******************************************************************
 * *                   .::::
 * *                 .::::::::
 * *                ::::::::::
 * *             ..:::::::::::
 * *          '::::::::::::
 * *            .:::::::::
 * *       '::::::::::::::..        女神助攻,流量冲天
 * *            ..::::::::::::.     永不宕机,代码无bug
 * *          ``:::::::::::::::
 * *           ::::``:::::::::'        .:::
 * *          ::::'   ':::::'       .::::::::
 * *        .::::'      ::::     .:::::::'::::
 * *       .:::'       :::::  .:::::::::' ':::::
 * *      .::'        :::::.:::::::::'      ':::::
 * *     .::'         ::::::::::::::'         ``::::
 * * ...:::           ::::::::::::'              ``::
 * *```` ':.          ':::::::::'                  ::::.
 * *                   '.:::::'                    ':'````.
 * ******************************************************************
 */

/* Private includes ----------------------------------------------------------*/
#include "blePro.h"
#include <string.h>
#include "stdio.h"
#include "stm32g0xx_hal.h"
#include "usart.h"
#include "user_data.h"
/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
volatile uint8_t rx_len                   = 0;  //接收一帧数据的长度
volatile uint8_t recv_end_flag            = 0;  //一帧数据接收完成标志
uint8_t          txDMAbuffer[BUFFER_SIZE] = {0};
uint8_t          rxDMAbuffer[BUFFER_SIZE] = {0};

uint8_t bleTxBuff[BUFFER_SIZE] = {0};
uint8_t bleRxBuff[BUFFER_SIZE] = {0};
uint8_t BleDataTemp[24]        = {0};
uint8_t rxCount                = 0;
uint8_t txCount                = 0;
uint8_t rxStep                 = 0;

ble_cmd_t bleCmdType  = BLE_PPP;
char      bleAddr[30] = {0};
char      bleName[30] = {0};

const cmd_map_st AT_command[17] = {
    {"+++",                           "AT+", "Mode=AT Mode"   }, // BLE_PPP
    {"AT+setBR 9600\r\n",             "AT+", ""               }, // BLE_SETBR
    {"AT+getName\r\n",                "AT+", ""               }, // BLE_GETNAME
    {"AT+setName=",                   "AT+", "restart effect!"}, // BLE_SETNAME
    {"AT+getAddr\r\n",                "AT+", ""               }, // BLE_GETADDR
    {"AT+setAddr=112233445566\r\n",   "AT+", "restart effect!"}, // BLE_SETADDR
    {"AT+getStatus\r\n",              "AT+", ""               }, // BLE_GETSTATUS
    {"AT+setAdvInt 80 100\r\n",       "AT+", "restart effect!"}, // BLE_SETADVINT
    {"AT+setConnInt 36 24 23 00\r\n", "AT+", ""               }, // BLE_SETCONNINT
    {"AT+disConnect\r\n",             "AT+", ""               }, // BLE_DISCONNECT
    {"AT+reStart\r\n",                "AT+", "restart now"    }, // BLE_RESTART
    {"AT+getPara\r\n",                "AT+", ""               }, // BLE_GETPARA
    {"AT+exit\r\n",                   "AT+", "Mode=Normal"    }, // BLE_EXIT
    {"AT+shutDown\r\n",               "AT+", "power off now!" }, // BLE_SHUTDOWN
    {"AT+reStore\r\n",                "AT+", "restart now"    }, // BLE_RESTORE
    {"AT+getInfo\r\n",                "AT+", ""               }, // BLE_GETINFO
    {"AT+help\r\n",                   "AT+", ""               }, // BLE_HELP
};

uint32_t bleRxTxEvent;

extern DMA_HandleTypeDef hdma_usart1_rx;
extern osThreadId_t      bleTid;
/* Private function prototypes -----------------------------------------------*/
void        HAL_UART_DMAStopRX(UART_HandleTypeDef *huart);
static void rxProcess(void);
static void bleInitialization(void);
void        pushCmdSendBuff(ble_cmd_t cmd, const char *Txdata);
static void uart_start_receive(void);
/* Private user code ---------------------------------------------------------*/

void bleProc(void const *argument)
{
    osThreadId_t thread_id = osThreadGetId();
    const char  *name      = osThreadGetName(thread_id);
    printf("threadName:%s\r\n", name);
    uart_start_receive();  //重新打开DMA接收
    osDelay(500);
    bleInitialization();

    while (1) {
        // rxProcess();
        // osDelay(10);
        bleRxTxEvent = osThreadFlagsWait(1, osFlagsWaitAny, 10);
        if (bleRxTxEvent == osFlagsErrorTimeout) {
            if ((regDataOk == 1) && (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10) == GPIO_PIN_RESET)) {
                regDataOk = 0;
                pushCmdSendBuff(BLE_TRANSMISSION, (void *)bleTxBuff);
            }
        } else {
            rxProcess();
        }
        if ((HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_10) == GPIO_PIN_RESET)) {
            boardBLEFlag = 1;
        } else {
            boardBLEFlag = 0;
        }
    }
}

static void bleInitialization(void)
{
    static char step = 0;
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);  // UART_SW
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);  // PWR_ON

    for (;;) {
        bleRxTxEvent = osThreadFlagsWait(1, osFlagsWaitAny, 10);
        if (bleRxTxEvent == osFlagsErrorTimeout) {
            switch (step) {
                case 0:
                    osDelay(6000);
                    step++;
                    break;
                case 1:
                    if (!commandMode) {
                        commandMode = 1;
                        commandOK   = 0;
                        pushCmdSendBuff(BLE_PPP, 0);
                        step = 2;
                    }
                    break;
                case 2:
                    if (commandOK) {
                        commandOK = 0;
                        pushCmdSendBuff(BLE_GETADDR, 0);
                        step = 3;
                    }
                    break;
                case 3:
                    if (commandOK) {
                        commandOK = 0;
                        pushCmdSendBuff(BLE_GETNAME, 0);
                        step = 4;
                    }
                    break;
                case 4:
                    if (commandOK) {
                        printf("bleName:%s,bleAddr:%s\r\n", bleName, bleAddr);
                        if (strncmp(bleName, bleAddr, 17)) {
                            commandOK = 0;
                            pushCmdSendBuff(BLE_SETNAME, bleAddr);
                            step = 5;
                        } else {
                            step = 7;
                        }
                    }
                    break;
                case 5:
                    if (commandOK) {
                        commandOK = 0;
                        pushCmdSendBuff(BLE_RESTART, 0);
                        step = 6;
                    }
                    break;
                case 6:
                    if (commandOK) {
                        step = 0;
                    }
                    break;
                case 7:
                    if (commandOK) {
                        commandOK = 0;
                        pushCmdSendBuff(BLE_EXIT, 0);
                        step = 8;
                    }
                    break;
                case 8:
                    if (commandOK) {
                        BLEInit     = 1;
                        bleInitFlag = 1;
                        return;
                    }
                    break;
                default:
                    break;
            }
        } else {
            rxProcess();
        }
    }
}

void pushCmdSendBuff(ble_cmd_t cmd, const char *Txdata)
{
    bleCmdType = cmd;
    memset(txDMAbuffer, 0, sizeof(txDMAbuffer));
    if (cmd == BLE_TRANSMISSION) {
        txCount = *(Txdata + 3) + 5;
        memcpy(txDMAbuffer, Txdata, txCount);
        HAL_UART_Transmit_DMA(&huart1, txDMAbuffer, txCount);
    } else {
        strcpy((char *)txDMAbuffer, AT_command[bleCmdType].cmd);
        if (Txdata) {
            strcat((char *)txDMAbuffer, Txdata);
            strcat((char *)txDMAbuffer, "\r\n");
        }
        HAL_UART_Transmit(&huart1, txDMAbuffer, strlen((const char *)txDMAbuffer), 0xffff);
    }
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(huart);
    UNUSED(Size);

    /* NOTE : This function should not be modified, when the callback is needed,
              the HAL_UARTEx_RxEventCallback can be implemented in the user file.
     */

    if (huart == &huart1) {
        rx_len = Size;  //计算接收到的数据长度
        if (rx_len > 0) {
            if (rxCount + rx_len > BUFFER_SIZE)
                rxCount = 0;
            memcpy(bleRxBuff + rxCount, rxDMAbuffer, rx_len);
            rxCount += rx_len;
            uartGetflag = 1;
            osThreadFlagsSet(bleTid, 0x01);
        }
        memset(rxDMAbuffer, 0, rx_len);  //清零接收缓冲区
        uart_start_receive();            //重新打开DMA接收
    }
}
static void uart_start_receive(void)
{
    HAL_UARTEx_ReceiveToIdle_DMA(&huart1, rxDMAbuffer, BUFFER_SIZE);
    __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
}

//串口接收空闲中断
// void Usart1Receive_IDLE(UART_HandleTypeDef *huart)
// {
//     if (RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))  //判断是否是空闲中断
//     {
//         uint8_t rx_len;
//         __HAL_UART_CLEAR_IDLEFLAG(&huart1);                             //清楚空闲中断标志（否则会一直不断进入中断）
//         HAL_UART_DMAStop(&huart1);                                      //停止本次DMA传输
//         rx_len = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);  //计算接收到的数据长度
//         if (rx_len > 0) {
//             if (rxCount + rx_len > BUFFER_SIZE)
//                 rxCount = 0;
//             memcpy(bleRxBuff + rxCount, rxDMAbuffer, rx_len);
//             rxCount += rx_len;
//             uartGetflag = 1;
//             osThreadFlagsSet(bleTid, 0x01);
//         }
//         memset(rxDMAbuffer, 0, rx_len);                           //清零接收缓冲区
//         HAL_UART_Receive_DMA(&huart1, rxDMAbuffer, BUFFER_SIZE);  //重新打开DMA接收
//     }
// }

// void HAL_UART_DMAStopRX(UART_HandleTypeDef *huart)
// {
//     CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
//     HAL_DMA_Abort(huart->hdmarx);
//     CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE_RXFNEIE | USART_CR1_PEIE));
//     CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
//     /* At end of Rx process, restore huart->RxState to Ready */
//     huart->RxState = HAL_UART_STATE_READY;
// }
// void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
// {
//     /* Prevent unused argument(s) compilation warning */
//     UNUSED(huart);

//     /* NOTE : This function should not be modified, when the callback is needed,
//             the HAL_UART_TxCpltCallback can be implemented in the user file.
//    */
// }

// void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
// {
//     /* Prevent unused argument(s) compilation warning */
//     UNUSED(huart);

//     /* NOTE : This function should not be modified, when the callback is needed,
//               the HAL_UART_ErrorCallback can be implemented in the user file.
//      */
// }

static void rxProcess(void)
{
    if (uartGetflag) {
        uartGetflag = 0;
        if (commandMode) {
            if ((strstr((const char *)bleRxBuff, "\r\n")) || (rxCount >= 25)) {
                uartRecOK = 1;
            }
        } else {
        again:
            if (rxStep == 0) {
                if (rxCount < 2)
                    goto rxContinue;
                if (memcmp(bleRxBuff, (void *)protocolHeader, 2) == 0)
                    rxStep = 1;
                else {
                    memcpy(bleRxBuff, bleRxBuff + 1, rxCount - 1);
                    rxCount--;
                    goto again;
                }
            }

            if (rxStep == 1) {
                if (rxCount < 4)
                    goto rxContinue;
                if (bleRxBuff[3] <= 15)
                    rxStep = 2;
                else {
                    memcpy(bleRxBuff, bleRxBuff + 2, rxCount - 2);
                    rxCount -= 2;
                    rxStep = 0;
                    goto again;
                }
            }

            if (rxStep == 2) {
                uint8_t checkSum, checkIndex;
                if (rxCount < bleRxBuff[3] + 5)
                    goto rxContinue;
                checkSum   = getCheckSum(bleRxBuff);
                checkIndex = bleRxBuff[3] + 4;
                if (checkSum == bleRxBuff[checkIndex]) {
                    uint8_t len = bleRxBuff[3] + 5;
                    memcpy(BleDataTemp, bleRxBuff, 20);
                    memcpy(bleRxBuff, bleRxBuff + len, rxCount - len);
                    rxCount -= len;
                    bleDataReday = 1;
                    // memset(bleRxBuff, 0, rxCount);
                    // rxCount = 0;
                    rxStep = 0;
                } else {
                    memcpy(bleRxBuff, bleRxBuff + 4, rxCount - 4);
                    rxCount -= 4;
                    rxStep = 0;
                    goto again;
                }
            }
        }
    }
rxContinue:
    if (uartRecOK) {
        char *atBak = strstr((const char *)bleRxBuff, "AT+ok");
        uartRecOK   = 0;
        if (atBak) {
            switch (bleCmdType) {
                case BLE_PPP:
                    if (strstr((const char *)bleRxBuff, "AT+")) {
                        commandOK = 1;
                    }
                    break;
                // case BLE_SETBR:                    break;
                case BLE_GETNAME:
                    commandOK = 1;
                    strncpy(bleName, atBak + strlen("AT+ok "), 20);
                    break;
                case BLE_SETNAME:
                    commandOK = 1;
                    if (strstr((const char *)bleRxBuff, AT_command[bleCmdType].bkKey)) {
                    }
                    break;
                case BLE_GETADDR:
                    commandOK = 1;
                    strncpy(bleAddr, atBak + strlen("AT+ok "), 20);
                    break;
                    // case BLE_GETSTATUS:break;
                    // case BLE_SETADVINT:break;
                    // case BLE_SETCONNINT:break;
                    // case BLE_DISCONNECT:break;
                case BLE_RESTART:
                    commandOK = 1;
                    if (strstr((const char *)bleRxBuff, AT_command[bleCmdType].bkKey)) {
                        commandMode = 0;
                    }
                    break;
                    // case BLE_GETPARA: break;
                case BLE_EXIT:
                    if (strstr((const char *)bleRxBuff, AT_command[bleCmdType].bkKey)) {
                        commandMode = 0;
                    }
                    commandOK = 1;
                    break;
                // case BLE_SHUTDOWN: break;
                // case BLE_RESTORE: break;
                // case BLE_GETINFO: break;
                // case BLE_HELP: break;
                default:
                    commandOK = 1;
                    break;
            }
        } else if (strstr((const char *)bleRxBuff, "AT+err")) {
            switch (bleCmdType) {
                case BLE_PPP:
                    commandOK = 1;
                    break;

                default:
                    break;
            }
        }
        memset(bleRxBuff, 0, rxCount);
        rxCount = 0;
    }
}
uint8_t getCheckSum(uint8_t *Cache)
{
    uint8_t checkSum = 0;
    uint8_t i;
    for (i = 0; i < (*(Cache + 3) + 4); i++) {
        checkSum += *(Cache + i);
    }
    return checkSum;
}
